Skip to content

Conversation

@TD-JBL
Copy link
Contributor

@TD-JBL TD-JBL commented Oct 20, 2025

I am using a customized OpenBLT bootloader which configures the clock system and the XSPI peripheral, then a Zephyr app is executed from external flash. I have not used MCUboot yet, but the problematic should be the same:
Zephyr must not change the clock path used for clocking the XSPI peripheral and must not change XSPI configuration nor set a VOLTAGE_SCALE not allowed for the already high cpu clock.

I have CONFIG_XIP=y set in my prj.conf, CONFIG_STM32_APP_IN_EXT_FLASH is automatically set because of its default $(DT_FLASH_PARENT_IS_XSPI) value.

With the changes in this PR, the combination of bootloader and zephyr runs fine on the nucleo_h7s3l8. But I'm not sure if this is the best way to handle things, so I open this up for discussion...

@TD-JBL
Copy link
Contributor Author

TD-JBL commented Oct 22, 2025

@erwango and @etienne-lms do you mind having a look at this?

{
int r = 0;

#if !defined(CONFIG_STM32_APP_IN_EXT_FLASH)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Completely skipping clock init could lead to misalignment of clock configuration between your bootloader and the application going unnoticed.
I'd suggest to follow what was done here: #88579

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, looking into that PR

{
int r = 0;

#if !defined(CONFIG_STM32_APP_IN_EXT_FLASH)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, looking into that PR

* turn off and reconfigure.)
*
*/
if (LL_RCC_GetSysClkSource() == LL_RCC_SYS_CLKSOURCE_STATUS_PLL1) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this a realistic usecase? Chainloading into an app in the small 64k internal flash next to the bootloader (not using XiP)?
Guard with #if !defined(CONFIG_STM32_APP_IN_EXT_FLASH) or remove block?

Disables setting the VOLTAGE_SCALE1 (VOS1) during soc_early_init_hook()
when CONFIG_STM32_APP_IN_EXT_FLASH is set.

Signed-off-by: Thomas Decker <[email protected]>
Add write-block-size and erase-block-size attributes to xspi nor flash
connected to xspi2. This is needed for mcuboot to handle flash access
of the ext_flash. The changes in the node structure is taken from the
stm32h7s78_dk board.

Update zephyr,flash-controller in samples/sysbuild/with_mcuboot/boards
/nucleo_h7s3l8.overlay to have CONFIG_STM32_APP_IN_EXT_FLASH set when
direct parent of flash is not XSPI but only the parent of the flash-
controller.

Signed-off-by: Thomas Decker <[email protected]>
Check the used XSPIx peripheral before calling the corresponding function
instead of hard-coded calling the LL_PWR_EnableXSPIM2() and
LL_SBS_EnableXSPI2SpeedOptim() during flash_stm32_xspi_init(...).

Signed-off-by: Thomas Decker <[email protected]>
Enable HSI clock node to fix get_hclk_frequency() returns 0 when called
from stm32_clock_control_init(). HSI on is the devices reset default
value anyway, but the STM32_HSI_FREQ define is set to 0 when not enabled.

Signed-off-by: Thomas Decker <[email protected]>
Add stm32_clock_control_get_status() function needed by flash_stm32_xspi
driver for handling XiP.

Signed-off-by: Thomas Decker <[email protected]>
Extent set_up_plls() to check if we are running the app in XiP and only
reconfigure PLLs and PLL outputs when they are not used in the clock path
of Q/O/X-SPI or have other constraints like XSPI AXI clock >= XSPI kernel
clock.

Signed-off-by: Thomas Decker <[email protected]>
@TD-JBL TD-JBL force-pushed the zephyr/startup_xip branch from 0aaf8a1 to 90bc050 Compare November 7, 2025 15:12
@sonarqubecloud
Copy link

sonarqubecloud bot commented Nov 7, 2025

@TD-JBL
Copy link
Contributor Author

TD-JBL commented Nov 7, 2025

I switched to the mcuboot bootloader and digged into sysbuild stuff. I tried to follow #88579 where things are done for the h5, but the h7 family is somehow more complicated (or my understanding of h5 details are wrong).

Commit soc: st: stm32: h7rsx: Disable core power and VOS config for XiP (39d3878)

The chain-loaded application must not switch to LL_PWR_REGU_VOLTAGE_SCALE1, because the bootloader most likely setup a fast core clock.

Commit boards: arm: st: nucleo_h7s3l8: Add *-block-size properties to xspi2 (d0aeb47)

  • Build output of mcuboot complained about not defined write-block-size and erase-block-size. Added those properties in the same way as it's done in the other h7rs eval board.
  • One must be careful to set zephyr,flash-controller = &ext_flash_ctrl to still have CONFIG_STM32_APP_IN_EXT_FLASH defined, as the first condition is not met anymore in soc/st/stm32/Kconfig.defconfig: config STM32_APP_IN_EXT_FLASH default $(DT_FLASH_PARENT_IS_XSPI) || $(DT_FLASH_CTRL_IS_XSPI_NOR)

Commit drivers: flash: stm32_xspi: Remove hard-coded XSPI2 dependency (6cbf0b8)

  • flash_stm32_xspi.c had hardcoded calls to LL_PWR_EnableXSPIM2() and LL_SBS_EnableXSPI2SpeedOptim()
  • added a check of the used XSPIx peripheral before calling the corresponding function of XSPI1/2

Commit dts: arm: st: h7rs: Enable HSI internal clock (70eb6e5)

  • I wondered why old_hclk_freq in stm32_clock_control_init(const struct device *dev) was always calculated to 0 and activated hsi clock note in the soc's dt to fix it
  • HSI on is the devices reset default value anyway, but the STM32_HSI_FREQ define is set to 0 when not enabled.

Commit drivers: clk: stm32_ll_h7: Add stm32_clock_control_get_status function (025fd7e)

  • added stm32_clock_control_get_status() in h7 clock driver similar to the h5 one
  • I thought this is needed by flash_stm32_xspi_init() with the call to clock_control_get_status(). But flash_stm32_xspi_init() does not seem to be called a second time when starting the chain-loaded app. Any explanations?

Commit drivers: clock: stm32_ll_h7: Disable clock configuration for XiP (90bc050)

Ok, now it gets ugly. I don't like this long list of #ifdefs and #defines, but I didn't find a short way implement this behaviour:

  • The chain-loaded application must not
    • modify the clock path to the Q/O/X-SPI peripheral
    • modify the HCLK when XSPI clock could be higher (XSPI axi vs. kernel clock constraint in h7rs)
    • switch the Q/O/X-SPI peripheral clock (by switching SYSCLOCK from PLL1 to HSI during re-config, when XSPI is clocked from HCLK) - not sure about this constraint, but at least for XSPI I can't image that's a good idea.
  • The chain-loaded application should be able to
    • re-configure all PLLs not used in the clock path to the Q/O/X-SPI peripheral
    • re-configure all PLL outputs not used in the clock path to the Q/O/X-SPI peripheral
  • That way a later change to the board's clock config can be done without updating mcuboot when not interfering with XiP function.

With these changes I am able to run the with_mcuboot example at a SYSCLK of 600MHz and the XSPI at 200MHz from PLL2S. Will hardfault without.
Changes to the nucleo_h7s3l8 board dt:

&pll {
	div-m = <2>;
	mul-n = <50>;
	div-p = <1>;
	div-q = <2>;
	div-r = <2>;
	div-s = <2>;
	div-t = <2>;
	clocks = <&clk_hse>;
	status = "okay";
};

/* PLL2 for clocking the xspi peripheral */
&pll2 {
	div-m = <12>;
	mul-n = <200>;
	div-p = <2>;
	div-q = <2>;
	div-r = <2>;
	div-s = <2>;
	div-t = <2>;
	clocks = <&clk_hse>;
	status = "okay";
};

&rcc {
	clocks = <&pll>;
	clock-frequency = <DT_FREQ_M(600)>;
	dcpre = <1>;
	hpre = <2>;	// BMPRE
	ppre1 = <2>;
	ppre2 = <2>;
	ppre4 = <2>;
	ppre5 = <2>;
	status = "okay";
};

The xspi2 node's clock setting must be changed to:

clocks =  <&rcc STM32_CLOCK(AHB5, 12)>,
		  <&rcc STM32_SRC_PLL2_S XSPI2_SEL(1)>, //0=HCLK5, 1=PLL2S, 2=PLL2T
		  <&rcc STM32_CLOCK(AHB5, 14)>; //only needed when XSPIM register access needed
clock-names = "xspix", "xspi_ker", "xspi_mgr";

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants